﻿/*    Copyright 2012 Robert Williams
    
    This file is part of FindUninstallString.

    FindUninstallString is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    FindUninstallString is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with FindUninstallString.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace WDT.AppInstaller
{
    /// <summary>
    /// Allows use of error names instead of numbers for error codes.
    /// Outputs corresponding description of selected error code.
    /// </summary>
    public class clsErrorCodes
    {
        #region ClassObjects
        /// <summary>
        /// Understandable descriptions of error codes.
        /// </summary>
        public enum ErrorCode : int
        {
            Success = 0,
            err05_AccessDenied = 5,
            err10_BadEnvironment = 10,
            err21_NotReady = 21,
            err80_FileExists = 80,
            err82_CannotMake = 82,
            err87_InvalidParameter = 87,
            err97_UnknownErrorCode = 97,
            err98_UnknownErrorCode = 98,
            err99_UnknownErrorCode = 99,
            err995_OperationAborted = 995,
            err1603_InstallFailure = 1603,
            err1013_Cannotwrite = 1013,
            err1223_Cancelled = 1223,
            err1271_MachineLocked = 1271,
            err1392_FileCorrupt = 1392,
            err1638_ProductVersion = 1638,
            err1639_Invalid_command_line = 1639,
            SuccessRebootRequired = 3010,
            err11011_BadCredentials = 11011
        }

        /// <summary>
        /// Method to sort an errorCodeTable
        /// </summary>
        public class errorCodeTableComparer
        {
            public static Int32 CompareByCode(errorCode a, errorCode b)
            {
                Int32 iComp = 0;

                if (a.code > b.code)
                {
                    iComp = 1;
                }
                else
                    if (a.code == b.code)
                    {
                        iComp = 0;
                    }
                    else
                        if (a.code < b.code)
                        {
                            iComp = -1;
                        }

                return iComp;
            }
        }

        /// <summary>
        /// An errorCode contains both a numeric code and a description.
        /// </summary>
        public class errorCode
        {
            private Int32 _code;
            private String _codeDescription;

            public Int32 code { get { return _code; } set { _code = value; } }
            public String codeDescription { get { return _codeDescription; } set { _codeDescription = value; } }

            public errorCode(Int32 code, String codeDescription)
            {
                _code = code;
                _codeDescription = codeDescription;
            }

        }

        private List<errorCode> errorCodeTable = new List<errorCode>();
        #endregion ClassObjects

        public clsErrorCodes()
        {
            try
            {
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.Success, "Success."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err05_AccessDenied, "Access is denied."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err10_BadEnvironment, "Wrong Operating System."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err21_NotReady, "User did not close a process listed in the prerequisites."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err80_FileExists, "The source file and destination are the same location."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err82_CannotMake, "Directory or file cannot be created."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err87_InvalidParameter, "The parameter is incorrect."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err97_UnknownErrorCode, "Fatal error during install."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err98_UnknownErrorCode, "Fatal error during install."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err99_UnknownErrorCode, "Fatal error during install."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err995_OperationAborted, "Fatal error during install."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1603_InstallFailure, "Fatal error during install."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1013_Cannotwrite, "The configuration registry key could not be written."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1223_Cancelled, "User did not close application."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1271_MachineLocked, "Prerequisite application is active and workstation is locked."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1392_FileCorrupt, "The file is corrupt."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1638_ProductVersion, "Installation has already been applied to the system."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err1639_Invalid_command_line, "Invalid command line argument."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.SuccessRebootRequired, "Reboot required to complete install."));
                errorCodeTable.Add(new errorCode((Int32)ErrorCode.err11011_BadCredentials, "Failed to elevate package."));
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Takes an error code and returns a description
        /// </summary>
        /// <param name="errCode"></param>
        /// <returns>A description of the error code</returns>
        public String GetErrorDescription(Int32 errCode)
        {
            String errorDescription = "Unexpected return code, Contact IMO";

            errorCode ec = errorCodeTable.Find(
                delegate(errorCode c)
                {
                    return c.code == errCode;
                }
            );

            if (ec != null)
            {
                errorDescription = ec.codeDescription;
            }

            return errorDescription;
        }

        /// <summary>
        /// Returns a String array containing a sorted list of error
        /// codes and their descriptions.
        /// </summary>
        /// <returns>Sorted list of error codes.</returns>
        public String[] getTable()
        {
            errorCodeTable.Sort(clsErrorCodes.errorCodeTableComparer.CompareByCode);

            Int32 numRows = errorCodeTable.Count;
            Int32 count = 0;
            String sErr = String.Empty;
            String[] eCodes = new String[numRows];

            foreach (errorCode ec in errorCodeTable)
            {
                sErr = String.Format("{0,6}: {1}", (ec.code), ec.codeDescription);
                eCodes[count++] = sErr;
            }

            return eCodes;
        }

        /// <summary>
        /// Prints Error Code Table to desired path.
        /// </summary>
        /// <param name="filePath"></param>
        [Conditional("DEBUG")]
        public void printErrorCodeTable(String filePath)
        {
            String[] ec = new String[this.errorCodeTable.Count];
            ec = this.getTable();
            StreamWriter SW;
            SW = File.CreateText(filePath);
            foreach (String s in ec)
            {
                SW.WriteLine(s);
            }

            SW.Close();
        }
    }
}
